package com.ehotting.edsta.circuitDesign.gen;


import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.ehotting.eaf.core.utils.StringUtils;
import com.ehotting.edsta.circuitDesign.SpringContextHelper;
import com.ehotting.edsta.circuitDesign.bean.*;
import com.ehotting.edsta.circuitDesign.enums.CircuitTypeEnum;
import com.ehotting.edsta.circuitDesign.bean.request.RequestCodeExecute;
import com.ehotting.edsta.circuitDesign.domain.EsCircuitType;
import com.ehotting.edsta.circuitDesign.enums.CodeDataTypeEnum;
import com.ehotting.edsta.circuitDesign.enums.RequestArgumentEnum;
import com.ehotting.edsta.circuitDesign.exception.LoggerTar;
import com.ehotting.edsta.circuitDesign.gen.arguments.ArgumentsScriptEngine;
import com.ehotting.edsta.circuitDesign.gen.element.helper.NumberHelper;
import com.ehotting.edsta.circuitDesign.service.IEsCircuitTypeService;
import com.ehotting.edsta.circuitDesign.uitls.CircuitThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;


@Service
public class SchemeEngine {

    private Logger logger = LoggerFactory.getLogger(SchemeEngine.class);

    @Autowired
    private CircuitThreadContext circuitThreadContext;

    @Autowired
    private IEsCircuitTypeService esCircuitTypeService;
    @Autowired
    private ArgumentsScriptEngine argumentsScriptEngine;
    @Autowired
    private CircuitEngine circuitEngine;


    public SchemePackageBean invoke(RequestCodeExecute inputParam,String mainProjectId){
        List<SchemeBean> schemeList =  genSchemeList(inputParam,mainProjectId);
        SchemePackageBean schemePackage = new SchemePackageBean(schemeList);
        return schemePackage;
    }



    public List<SchemeBean> genSchemeList(RequestCodeExecute inputParam,String mainProjectId){
        List<EsCircuitType> circuitTypeList = esCircuitTypeService.selectEsCircuitTypeList(null);
        AllMapBean contextMap = argumentsScriptEngine.invoke(circuitTypeList,inputParam);
        List<SchemeBean> schemeList = invoke(contextMap,mainProjectId);
        return schemeList;
    }


    public List<SchemeBean> invoke(AllMapBean contextMap,String mainProjectId){
        SchemeBean scheme = new SchemeBean();
        scheme.getAll().putAll(contextMap);
        List<SchemeBean> startSchemeList = new ArrayList<>();
        startSchemeList.add(scheme);

        SchemeEngine schemeEngine= SpringContextHelper.getBean(SchemeEngine.class);

        /**1、传感器计算**/
        List<SchemeBean> sensorSchemeList  = schemeEngine.invoke(startSchemeList,CircuitTypeEnum.SENSOR,mainProjectId);

        /**2、处理器计算**/
        List<SchemeBean> controllerSchemeList = schemeEngine.invoke(sensorSchemeList,CircuitTypeEnum.CONTROLLER,mainProjectId);

        /**3、电源计算**/
        List<SchemeBean> powerSchemeList = schemeEngine.invoke(controllerSchemeList,CircuitTypeEnum.POWER,mainProjectId);

        /**
         *清空全局变量
         */
        clearGlobalVar(powerSchemeList);

        /**
         * 使用多线程进行方案匹配
         *     1.启动顺序有先后
         *     2.完成顺序有先后
         *     3.一个屋子的物品相同，摆放位置不同
         * 使用所有电路id组成字符串进行排序
         */
        powerSchemeList = powerSchemeList.stream()
                .sorted(Comparator.comparing(SchemeBean::getIdStr))
                .collect(Collectors.toList());
        return powerSchemeList;
    }

    public void clearGlobalVar(List<SchemeBean> powerSchemeList){
        for(SchemeBean schemeBean : powerSchemeList){
            schemeBean.setAll(null);
            StringBuffer stringBuffer = new StringBuffer();
            Collection<CircuitPackageBean> schemeBeanValues = schemeBean.getCircuit().values();
            for (CircuitPackageBean packageBean : schemeBeanValues){
                Collection<CircuitGroupBean> packageBeanValues = packageBean.values();
                for(CircuitGroupBean groupBean : packageBeanValues){
                    Set<Long> groupBeanKeys = groupBean.keySet();
                    for(Long keyId : groupBeanKeys){
                        if(stringBuffer.length() > 0){
                            stringBuffer.append('-').append(keyId);
                            continue;
                        }
                        stringBuffer.append(keyId);
                    }

                }

            }
            schemeBean.setIdStr(stringBuffer.toString());
        }
    }

    public List<SchemeBean> invoke(List<SchemeBean> schemeList,CircuitTypeEnum circuitTypeEnum,String mainProjectId){
        logger.info("Start circuitTypeEnum.getName():{}",circuitTypeEnum.getName());
        EsCircuitType circuitType= esCircuitTypeService.selectEsCircuitTypeByCircuitType(circuitTypeEnum);
        List<SchemeBean> scList = invoke(circuitType, schemeList, mainProjectId);

        return scList;
    }


    private List<SchemeBean> invoke(EsCircuitType circuitType,List<SchemeBean> schemeList,String mainProjectId){
        final String[] errMsg = {null};
        // 停止匹配
        if(!circuitThreadContext.isActive()){
            Thread.currentThread().interrupt();
        }
        List<SchemeBean> scList = new ArrayList<>();
        MultiThreadQueueHelper<SchemeBean> multiThreadQueueHelper = new MultiThreadQueueHelper<SchemeBean>() {
            @Override
            public void task(SchemeBean schemeBean) {

                try {
                    List<SchemeBean> newSchemeList = invoke(circuitType, schemeBean,mainProjectId);
                    logger.info("newSchemeList.size():{}", newSchemeList.size());
                    if(newSchemeList.size() > 0){
                        scList.addAll(newSchemeList);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    errMsg[0] = StringUtils.isEmpty(e.getMessage()) ?"generateError:系统内部错误" :e.getMessage();
                }
            }
        };
        multiThreadQueueHelper.setCircuitThreadContext(circuitThreadContext);

        try {
            Thread.sleep(200);
            multiThreadQueueHelper.execute(schemeList);
        } catch (Exception e) {
            e.printStackTrace();
            errMsg[0] = StringUtils.isEmpty(e.getMessage()) ?"generateError:系统内部错误" :e.getMessage();
        }
        String eMsg = "电路类型【"+circuitType.getCircuitType().getName()+"】没有符合条件的电路模块";
        AssertUtil.isTrue(!CollectionUtil.isEmpty(scList),errMsg[0]==null?eMsg:errMsg[0]);

        return scList;
    }


    private List<SchemeBean> invoke(EsCircuitType circuitType,SchemeBean scheme,String mainProjectId){

        List<CircuitPackageBean> circuitPackageList = circuitEngine.invoke( circuitType, scheme.getAll(),mainProjectId);
        logger.info("circuitPackageList.size():{}",circuitPackageList.size());
        List<SchemeBean> schemeList = new ArrayList();

        for(CircuitPackageBean circuitPackage : circuitPackageList){
            SchemeBean newScheme = new SchemeBean();
            /**复制已经计算的模块**/
            newScheme.getCircuit().putAll(scheme.getCircuit());
            /**加入新计算模块**/
            newScheme.getCircuit().put(circuitType.getCircuitType().getCode(),circuitPackage);

            AllMapBean allMap = scheme.getAll().clone();
            if(circuitType.getCircuitType()==CircuitTypeEnum.SENSOR){
                //todo 设置全局变量 ok
                Map<String,Object> map = new HashMap<>();
                map.put(ProCodeName.Analog_Channel_Num,circuitPackage.getAnalogueOutChannelCount());
                map.put(ProCodeName.Digit_Channel_Num,circuitPackage.getDigitalOutChannelCount());
                map.put(ProCodeName.Scheme_Channel_Num,circuitPackage.getAnalogueChannelCount());
                map.put(ProCodeName.Scheme_Sample,circuitPackage.getMaxSample());
                map.put(ProCodeName.Digital_Channel_Count,circuitPackage.getDigitalChannelCount());
                map.put(ProCodeName.Scheme_Sampling_Length,circuitPackage.getMaxSamplingLength());
                map.put(ProCodeName.Adc_Sampling_Bit,circuitPackage.getMaxAdcSamplingBit());
                allMap.put(CircuitTypeEnum.SENSOR,CodeDataTypeEnum.PROP,map);
            }

            /**全局参数复制**/
            newScheme.getAll().putAll(allMap);
            List<Map<String, Object>> allList = circuitPackage.getPropList();
            /**追加属性**/
            for(Map<String, Object> o : allList){
                newScheme.getAll().append(circuitType.getCircuitType(), CodeDataTypeEnum.PROP,o);
            }

            schemeList.add(newScheme);
        }
        return schemeList;
    }


    private boolean isNeedDigitalCircuit(RequestCodeExecute inputParam){
        String digitalNum = inputParam.getData().get(RequestArgumentEnum.DIGITAL_NUM.getCode()).toString();
        if(NumberHelper.isInteger(digitalNum) && NumberHelper.parseInteger(digitalNum)>0){
            return true;
        }
        return false;
    }



}